﻿#region using
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Linq;

using DbmlManager.Lib.Database;
using DbmlManager.Lib.Utility;
#endregion

namespace DbmlManager.App.CommandLine
{
  class Program
  {
    // Private Static Variables

    #region Private Static Variables
    private static string _dbmlFileName = null;
    private static string _command = null;
    private static string _tableName = null;
    private static string _sqlServerName = null;
    private static string _dbName = null;
    private static bool   _modifyDb = false;
    #endregion

    // Application Entry Point

    #region Main(string[] args)
    static void Main(string[] args)
    {
      if (!ProcessArgs(args))
        return;

      RunCommand();
    }
    #endregion

    // Private Static Methods

    #region ProcessArgs(string[] args)
    private static bool ProcessArgs(string[] args)
    {
      int x;

      for (x = 0; x < args.Length - 1; x++)
      {
        if (args[x][0] != '/' && args[x][0] != '-')
          break; // End of options

        // Options are specified in the form
        //   -option:optionInfo

        Match match = Regex.Match(args[x], "^[/-](?<option>[^:]*)($|:(?<optionInfo>.*))");
        if (match == null)
          break;

        string option = match.Groups["option"].Value;
        string optionInfo = null;
        if (match.Groups["optionInfo"] != null)
          optionInfo = match.Groups["optionInfo"].Value;

        switch (option.ToLower())
        {
          case "dbml":
            if (optionInfo == null)
            {
              Console.WriteLine("No filename specified");
              return false;
            }

            _dbmlFileName = optionInfo;
            break;

          case "table":
          case "tablename":
            if (optionInfo == null)
            {
              Console.WriteLine("No table name specified");
              return false;
            }

            _tableName = optionInfo;
            break;

          case "sql":
          case "sqlserver":
            if (optionInfo == null)
            {
              Console.WriteLine("No SQL Server name specified");
              return false;
            }

            _sqlServerName = optionInfo;
            break;

          case "db":
          case "database":
          case "dbname":
            if (optionInfo == null)
            {
              Console.WriteLine("No database name specified");
              return false;
            }

            _dbName = optionInfo;
            break;

          case "modify":
          case "modifydb":
            _modifyDb = true;
            break;

          default:
            Console.WriteLine("Option '{0}' not recognized", option);
            return false;
        }
      }

      if (x >= args.Length)
      {
        Console.WriteLine("No filename specified");
        return false;
      }

      _command = args[x];
      return true;
    }
    #endregion

    #region RunCommand()
    private static void RunCommand()
    {
      switch (_command.ToLower())
      {
        case "listtables":
        case "tables":
          ListTables();
          break;

        case "tableinfo":
          TableInfo();
          break;

        case "dbconnect":
        case "connectdb":
        case "testdb":
        case "testconnect":
        case "testdbconnect":
          TestDatabaseConnection();
          break;

        case "databases":
        case "listdb":
        case "listdatabases":
          ListDatabases();
          break;

        case "dbexists":
        case "exists":
          DbExists();
          break;

        case "createdb":
        case "createdatabase":
          CreateDb();
          break;

        default:
          Console.WriteLine("Command '{0} not recognized.", _command);
          break;
      }
    }
    #endregion

    // Command Processing Methods

    #region TableInfo()
    private static void TableInfo()
    {
      if (_dbmlFileName == null)
      {
        Console.WriteLine("No dbml filename was specified");
        return;
      }

      if (_tableName == null)
      {
        Console.WriteLine("No table name was specified");
      }

      Database dbml = new Database(_dbmlFileName);

      var tables = from table in dbml.Tables where table.Type.Name == _tableName select table;
      if (tables.Count() == 0)
      {
        Console.WriteLine("Table '{0}' not found", _tableName);
        return;
      }

      if (tables.First().Type == null)
      {
        Console.WriteLine("Table '{0}' has no type definition", _tableName);
        return;
      }

      var columns = from column in tables.First().Type.Columns select column;
      if (columns.Count() == 0)
      {
        Console.WriteLine("Table '{0}' has no columns defined", _tableName);
        return;
      }

      foreach (Column column in columns)
        Console.WriteLine("Column: {0} {1}", column.Name, column.IsPrimaryKey ? "(Primary Key)" : string.Empty);
    }
    #endregion

    #region ListTables()
    private static void ListTables()
    {
      if (_dbmlFileName == null)
      {
        Console.WriteLine("No dbml filename was specified");
        return;
      }

      Database dbml = new Database(_dbmlFileName);

      Console.WriteLine("\nThere are {0} table(s) defined:\n", dbml.Tables.Count);

      foreach (Table table in dbml.Tables)
        Console.WriteLine("Table: {0}", table.Type.Name);
    }
    #endregion

    #region TestDatabaseConnection()
    private static void TestDatabaseConnection()
    {
      if (_sqlServerName == null)
      {
        Console.WriteLine("No SQL Server name was specified");
        return;
      }

      DbConnectionInfo dbci = new DbConnectionInfo();
      dbci.ServerName = _sqlServerName;

      try
      {
        Console.WriteLine("Connecting to SQL Server '{0}' ...", _sqlServerName);
        IDbConnection connection = dbci.Connection();
        connection.Open();
        Console.WriteLine("Connection successful.");
        Console.WriteLine("Closing connection ...");
        connection.Close();
        Console.WriteLine("Connection closed successfully.");
      }
      catch (Exception ex)
      {
        Console.WriteLine("Could not open a connection to SQL Server '{0}'", _sqlServerName);
        Console.WriteLine(ex.Message);
      }
    }
    #endregion

    #region ListDatabases()
    private static void ListDatabases()
    {
      if (_sqlServerName == null)
      {
        Console.WriteLine("No SQL Server name was specified");
        return;
      }

      DbConnectionInfo dbci = new DbConnectionInfo();
      dbci.ServerName = _sqlServerName;

      try
      {
        SqlDbCreator creator = new SqlDbCreator(dbci);

        foreach (string db in creator.GetDatabases())
          Console.WriteLine(db);
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }
    #endregion

    #region DbExists()
    private static void DbExists()
    {
      if (_sqlServerName == null)
      {
        Console.WriteLine("No SQL Server name was specified");
        return;
      }

      if (_dbName == null)
      {
        Console.WriteLine("No database name was specified");
        return;
      }

      DbConnectionInfo dbci = new DbConnectionInfo();
      dbci.ServerName = _sqlServerName;

      try
      {
        SqlDbCreator creator = new SqlDbCreator(dbci);
        Console.WriteLine(creator.DbExists(_dbName) ? "Yes" : "No");
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }
    #endregion

    #region CreateDb()
    private static void CreateDb()
    {
      if (_sqlServerName == null)
      {
        Console.WriteLine("No SQL Server name was specified");
        return;
      }

      if (_dbName == null)
      {
        Console.WriteLine("No database name was specified");
        return;
      }

      DbConnectionInfo dbci = new DbConnectionInfo();
      dbci.ServerName = _sqlServerName;

      try
      {
        SqlDbCreator creator = new SqlDbCreator(dbci);

        if (!_modifyDb)
        {
          Console.WriteLine(creator.GetCreateDbSql(_dbName));
          return;
        }

        if (creator.DbExists(_dbName))
        {
          Console.WriteLine("Database '{0}' already exists.", _dbName);
          return;
        }

        creator.CreateDb(_dbName);

        if (creator.DbExists(_dbName))
          Console.WriteLine("Database '{0}' was successfully created.", _dbName);
        else
          Console.WriteLine("It appears there was a problem creating database '{0}'", _dbName);
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }
    #endregion
  }
}
